package com.easychat.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import javax.annotation.Resource;

import com.easychat.entity.config.AppConfig;
import com.easychat.entity.constants.Constants;
import com.easychat.entity.dto.MessageSendDto;
import com.easychat.entity.dto.TokenUserInfoDto;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.*;
import com.easychat.entity.query.*;
import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.*;
import com.easychat.redis.RedisComponent;
import com.easychat.service.ChatSessionUserService;
import com.easychat.service.GroupInfoService;
import com.easychat.service.UserContactService;
import com.easychat.utils.CopyTools;
import com.easychat.utils.StringTools;
import com.easychat.websocket.netty.ChannelContextUtils;
import com.easychat.websocket.netty.MessageHandler;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


/**
 * 群组表 业务接口实现
 */
@Service("groupInfoService")
public class GroupInfoServiceImpl implements GroupInfoService {

    @Resource
    private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;
    @Resource
    private UserContactMapper userContactMapper;
    @Resource
    private AppConfig appConfig;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private UserContactService userContactService;
    @Resource
    private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

    @Resource
    private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;
    @Resource
    private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

    @Resource
    private ChannelContextUtils channelContextUtils;
    @Resource
    private MessageHandler messageHandler;
    @Resource
    private ChatSessionUserService chatSessionUserService;
    @Resource
    @Lazy
    private GroupInfoService groupInfoService;
    @Resource
    private UserInfoMapper<UserInfo,UserInfoQuery> userInfoMapper;

    /**
     * 根据条件查询列表
     */
    @Override
    public List<GroupInfo> findListByParam(GroupInfoQuery param) {
        return this.groupInfoMapper.selectList(param);
    }

    /**
     * 根据条件查询列表
     */
    @Override
    public Integer findCountByParam(GroupInfoQuery param) {
        return this.groupInfoMapper.selectCount(param);
    }

    /**
     * 分页查询方法
     */
    @Override
    public PaginationResultVO<GroupInfo> findListByPage(GroupInfoQuery param) {
        int count = this.findCountByParam(param);
        int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

        SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
        param.setSimplePage(page);
        List<GroupInfo> list = this.findListByParam(param);
        PaginationResultVO<GroupInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
        return result;
    }

    /**
     * 新增
     */
    @Override
    public Integer add(GroupInfo bean) {
        return this.groupInfoMapper.insert(bean);
    }

    /**
     * 批量新增
     */
    @Override
    public Integer addBatch(List<GroupInfo> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.groupInfoMapper.insertBatch(listBean);
    }

    /**
     * 批量新增或者修改
     */
    @Override
    public Integer addOrUpdateBatch(List<GroupInfo> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.groupInfoMapper.insertOrUpdateBatch(listBean);
    }

    /**
     * 多条件更新
     */
    @Override
    public Integer updateByParam(GroupInfo bean, GroupInfoQuery param) {
        StringTools.checkParam(param);
        return this.groupInfoMapper.updateByParam(bean, param);
    }

    /**
     * 多条件删除
     */
    @Override
    public Integer deleteByParam(GroupInfoQuery param) {
        StringTools.checkParam(param);
        return this.groupInfoMapper.deleteByParam(param);
    }

    /**
     * 根据GroupId获取对象
     */
    @Override
    public GroupInfo getGroupInfoByGroupId(String groupId) {
        return this.groupInfoMapper.selectByGroupId(groupId);
    }

    /**
     * 根据GroupId修改
     */
    @Override
    public Integer updateGroupInfoByGroupId(GroupInfo bean, String groupId) {
        return this.groupInfoMapper.updateByGroupId(bean, groupId);
    }

    /**
     * 根据GroupId删除
     */
    @Override
    public Integer deleteGroupInfoByGroupId(String groupId) {
        return this.groupInfoMapper.deleteByGroupId(groupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void savaGroup(GroupInfo groupInfo, MultipartFile avatarFile, MultipartFile avatarCoverFile) throws IOException {
        Date curDate = new Date();
        //判断是新增还是修改
        if (groupInfo.getGroupId() == null) {//创建群
            //判断群主创建群数是否超过限制
            isMaxCount(groupInfo);

            if (null == avatarFile) {
                throw new BusinessException(ResponseCodeEnum.CODE_600);
            }
            //新增
            groupInfo.setCreateTime(curDate);
            groupInfo.setGroupId(StringTools.getGroupId(11)); //生成群组ID
            groupInfoMapper.insert(groupInfo);

            //将群组变成联系人
            UserContact userContact = new UserContact();
            userContact.setUserId(groupInfo.getGroupOwnerId());
            userContact.setContactId(groupInfo.getGroupId());
            userContact.setStatus(UserContactStatusEnum.FRIEND.getCode());
            userContact.setContactType(UserContactTypeEnum.GROUP.getType());
            userContact.setCreateTime(curDate);
            userContact.setLastUpdateTime(curDate);
            userContactMapper.insert(userContact);

            // 创建会话
            //chat_session
            String sessionId = StringTools.getChatSessionIdGroup(groupInfo.getGroupId());
            ChatSession chatSession = new ChatSession();
            chatSession.setSessionId(sessionId);
            chatSession.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatSession.setLastReceiveTime(curDate.getTime());
            chatSessionMapper.insert(chatSession);
            //chat session user
            ChatSessionUser chatSessionUser = new ChatSessionUser();
            chatSessionUser.setUserId(groupInfo.getGroupOwnerId());
            chatSessionUser.setContactId(groupInfo.getGroupId());
            chatSessionUser.setSessionId(sessionId);
            chatSessionUser.setContactName(groupInfo.getGroupName());
//            chatSessionUserMapper.insert(chatSessionUser);
            chatSessionUserService.add(chatSessionUser);


            //将群组添加到联系人缓存
            redisComponent.addUserContact(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());
            //将群的channel加入到map中
            channelContextUtils.addUser2Group(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());
            // chat message
            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setSessionId(sessionId);
            chatMessage.setMessageType(MessageTypeEnum.GROUP_CREATE.getType());
            chatMessage.setMessageContent(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatMessage.setSendUserId(null);
            chatMessage.setSendUserNickName(null);
            chatMessage.setSendTime(curDate.getTime());
            chatMessage.setContactId(groupInfo.getGroupId());
            chatMessage.setContactType(UserContactTypeEnum.GROUP.getType());
            chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
            chatMessageMapper.insert(chatMessage);
            //发送ws消息
            chatSessionUser.setLastReceiveTime(curDate.getTime());
            chatSessionUser.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatSessionUser.setMemberCount(1);

            MessageSendDto messageSendDto = CopyTools.copy(chatMessage, MessageSendDto.class);
            messageSendDto.setExtendData(chatSessionUser);
            messageSendDto.setLastMessage(chatSessionUser.getLastMessage());
            messageHandler.sendMessage(messageSendDto);

        } else {//修改群

            String contactNameUpdate =groupInfo.getGroupName();
            //查询这个群的群主
            GroupInfo dbInfo = groupInfoMapper.selectByGroupId(groupInfo.getGroupId());
            // 判断是否是群主或者管理员 修改的信息
            if (!Objects.equals(dbInfo.getGroupOwnerId(), groupInfo.getGroupOwnerId())) {
                throw new BusinessException(ResponseCodeEnum.CODE_600);
            }

            //修改
            groupInfoMapper.updateByGroupId(groupInfo, groupInfo.getGroupId());
            //修改其他表的冗余信息 并 发送ws通知
            chatSessionUserService.updateRedundanceInfo(contactNameUpdate,groupInfo.getGroupId());
        }
        if (null == avatarFile) {
            return;
        }
        // 文件拷贝！

        //文件夹路径
        String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;
        //具体文件路径
        File targetFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR_NAME);
        if (!targetFileFolder.exists()) {
            targetFileFolder.mkdirs();//创建文件夹
        }
        // 文件名
        String filePath = targetFileFolder.getPath() + "/" + groupInfo.getGroupId() + Constants.IMAGE_SUFFIX;
        avatarFile.transferTo(new File(filePath));
        avatarCoverFile.transferTo(new File(filePath + Constants.COVER_IMAGE_SUFFIX));

    }

    /**
     * 解散群聊
     *
     * @param groupOwnerId 群主id
     * @param groupId      群id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dissolutionGroup(String groupOwnerId, String groupId) {
        //判断是否是群主
        GroupInfo dbInfo = groupInfoMapper.selectByGroupId(groupId);
        if (!dbInfo.getGroupOwnerId().equals(groupOwnerId)) {
            throw new BusinessException("非群主不能解散群聊");
        }
        //1.删除groupinfo表  只是改变状态为禁用
        GroupInfo updateGroupInfo = new GroupInfo();
        updateGroupInfo.setStatus(GroupStatusEnum.DELETED.getCode());
        groupInfoMapper.updateByGroupId(updateGroupInfo, groupId);
        //2.删除usercontact表  只是改变与群的状态
        UserContact updateUserContact = new UserContact();
        updateUserContact.setStatus(UserContactStatusEnum.DELETE_BE.getCode());

        UserContactQuery userContactQuery = new UserContactQuery();
        userContactQuery.setContactId(groupId);
        userContactQuery.setContactType(UserContactTypeEnum.GROUP.getType());
        userContactService.updateByParam(updateUserContact, userContactQuery);

        //  移除相关群员的联系人的缓存， （不能与群里的成员发消息了）
        // 1.更新回话消息 2.记录群消息 3.发送群解散通知消息
        //redis中记录的是在线的联系人 数据库记录的是所有的联系人
        List<UserContact> userContactList  = userContactMapper.selectList(userContactQuery);
        for (UserContact userContact : userContactList) {
            redisComponent.removeUserContact(userContact.getUserId(),userContact.getContactId());
        }

        //chat session
        String message = MessageTypeEnum.DISSOLUTION_GROUP.getInitMessage();
        Date curDate = new Date();
        String sessionId=StringTools.getChatSessionIdGroup(groupId);
        ChatSession chatSession = new ChatSession();
        chatSession.setLastMessage(message);
        chatSession.setLastReceiveTime(curDate.getTime());
        chatSessionMapper.updateBySessionId(chatSession,sessionId);
        //chat message
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setSessionId(sessionId);
        chatMessage.setMessageType(MessageTypeEnum.DISSOLUTION_GROUP.getType());
        chatMessage.setMessageContent(message);
        chatMessage.setSendTime(curDate.getTime());
        chatMessage.setContactId(groupId);
        chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
        chatMessageMapper.insert(chatMessage);
        MessageSendDto messageSendDto = CopyTools.copy(chatMessage,MessageSendDto.class);
        messageHandler.sendMessage(messageSendDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrRemoveGroupUser(String groupId, String contactIds, Integer opType, TokenUserInfoDto tokenUserInfo) {
        GroupInfo groupInfo = groupInfoMapper.selectByGroupId(groupId);
        //判断群是否存在 || 是否是群主
        if (groupInfo==null){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        if (!groupInfo.getGroupOwnerId().equals(tokenUserInfo.getUserId())){
            throw new BusinessException("非群主不能操作");
        }
        String[] contactIdsArray = contactIds.split(",");
        for (String contactId : contactIdsArray) {
            //移除
            if(opType.equals(Constants.ZERO)){
                groupInfoService.leaveGroup(contactId, groupId, MessageTypeEnum.REMOVE_GROUP);
            }else if (opType.equals(Constants.ONE)){
            //添加
                userContactService.addContact(contactId,null,groupId,UserContactTypeEnum.GROUP.getType(), null);
            }

        }
    }

    /**
     * 退出群聊
     * @param userId  退出者id
     * @param groupId 群id
     * @param messageTypeEnum 消息类型 LEAVE_GROUP(11,"%s退出群聊","退出群聊"),
     *                               REMOVE_GROUP(12,"%s被管理员移除群聊","被管理员移除群聊"),
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void leaveGroup(String userId, String groupId, MessageTypeEnum messageTypeEnum) {
        //校验操作
        GroupInfo groupInfo = groupInfoService.getGroupInfoByGroupId(groupId);
        if (null==groupInfo){
            throw new BusinessException("群不存在！");
        }
        if (userId.equals(groupInfo.getGroupOwnerId())){
            throw new BusinessException("群主不能退出群聊");
        }

        //移除操作
        Integer count = userContactService.deleteUserContactByUserIdAndContactId(userId, groupId);
        if (count==0){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        //发送ws 消息
        Date curDate = new Date();
        UserInfo userInfo =  userInfoMapper.selectByUserId(userId);
        String sessionId = StringTools.getChatSessionIdGroup(groupId);
        String messageContent = String.format(messageTypeEnum.getInitMessage(), userInfo.getNickName());
        //chat session
        ChatSession chatSession = new ChatSession();
        chatSession.setLastReceiveTime(curDate.getTime());
        chatSession.setLastMessage(messageContent);//改
        chatSession.setSessionId(sessionId);
        //chat message
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setSessionId(sessionId);
        chatMessage.setSendTime(curDate.getTime());
        chatMessage.setContactType(UserContactTypeEnum.GROUP.getType());
        chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
        chatMessage.setMessageType(messageTypeEnum.getType());
        chatMessage.setContactId(groupId);
        chatMessage.setMessageContent(messageContent);
        chatMessageMapper.insert(chatMessage);

        UserContactQuery userContactQuery = new UserContactQuery();
        userContactQuery.setContactId(groupId);
        userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getCode());
        Integer memberCount = this.userContactMapper.selectCount(userContactQuery);

        MessageSendDto messageSendDto = CopyTools.copy(chatMessage, MessageSendDto.class);
        messageSendDto.setExtendData(userId);
        messageSendDto.setMemberCount(memberCount);
        messageHandler.sendMessage(messageSendDto);

    }

    public void isMaxCount(GroupInfo groupInfo) {
        //获取群主创建的群数
        GroupInfoQuery groupInfoQuery = new GroupInfoQuery();
        groupInfoQuery.setGroupOwnerId(groupInfo.getGroupOwnerId());
        Integer count = groupInfoMapper.selectCount(groupInfoQuery);

        //获取系统设置最大群组数
        Integer maxGroupCount = redisComponent.getSysSettingDto().getMaxGroupCount();
        if (count >= maxGroupCount) {
            throw new BusinessException("最多支持创建" + maxGroupCount + "个群组");
        }

    }
}